package com.zsc.boot.service.impl;
import java.util.*;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.zsc.boot.bean.User;
import com.zsc.boot.common.ErrorType;
import com.zsc.boot.contant.UserContant;
import com.zsc.boot.exception.BusinessException;
import com.zsc.boot.service.UserService;
import com.zsc.boot.mapper.UserMapper;
import jdk.nashorn.internal.parser.Token;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.zsc.boot.contant.UserContant.ADMIN_ROLE;
import static com.zsc.boot.contant.UserContant.USER_LOGIN_STATE;

/**
 *
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService{

    @Resource
    private UserMapper userMapper;

    //盐值:加密密码
    private static final String SALT = "hines";


    /**
     * 注册逻辑
     *
     * @param userAccount 用户名
     * @param userPassword 密码
     * @param checkPassword 校验码
     * @return
     */
    @Override
    public long UserRegister(String username,String userAccount, String userPassword, String checkPassword) {
        /*校验*/

        //1、使用lang3的方法快速判断这三个字段是不是空的
        if(StringUtils.isAnyBlank(username,userAccount,userPassword,checkPassword)){
            throw new BusinessException(ErrorType.PARAMS_ERROR);
        }

        //2、根据所写的注册逻辑判断

        /*账户不小于4*/
        if(userAccount.length() < 4){
            throw new BusinessException(ErrorType.PARAMS_ERROR);
        }

        /*密码不小于8*/
        if(userPassword.length() < 8 || checkPassword.length() < 8){
            throw new BusinessException(ErrorType.PARAMS_ERROR);
        }

        /*账户不能包含特殊字符*/
        String vaildPattern = "[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";//这里表示特殊字符
        Matcher matcher = Pattern.compile(vaildPattern).matcher((userAccount));
        if(matcher.find()){ //找到特殊字符就返回-1
            throw new BusinessException(ErrorType.PARAMS_ERROR);

        }

        /*校验密码相同*/
        if(!userPassword.equals(checkPassword)){
            throw new BusinessException(ErrorType.PARAMS_ERROR);
        }

        /*账号不能重复*/
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userAccount",userAccount);//这里的userAccount是上面形参传过来的，这条语句表示根据这个userAccount查询有多少条语句
        //这里的this是指当前UserServiceImpl的对象
        long count = this.count(queryWrapper);
        if(count>0){
            throw new BusinessException(ErrorType.PARAMS_ERROR);
        }

        /*密码加密*/
        String newPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());

        /*插入数据到数据库中*/
        User user = new User();
        user.setUsername(username);
        user.setUserAccount(userAccount);
        user.setUserPassword(newPassword);
        boolean result = this.save(user);
        //如果插入不成功就抛出异常
        if(!result){
            throw new BusinessException(ErrorType.PARAMS_ERROR);
        }
        return user.getId(); //因为返回值是long型的id（注册了一个账号就返回一个id）
    }


    /**
     * 登录逻辑
     * @param userAccount 用户名
     * @param userPassword 密码
     * @return
     */
    @Override
    public User UserLogin(String userAccount, String userPassword, HttpServletRequest request) {
        /*校验*/

        //1、使用lang3的方法快速判断这三个字段是不是空的
        if(StringUtils.isAnyBlank(userAccount,userPassword)){
            throw new BusinessException(ErrorType.NULL_ERROR);
        }

        //2、根据所写的注册逻辑判断

        /*账户不小于4*/
        if(userAccount.length() < 4){
            throw new BusinessException(ErrorType.PARAMS_ERROR);
        }

        /*密码不小于8*/
        if(userPassword.length() < 8 ){
            throw new BusinessException(ErrorType.PARAMS_ERROR);
        }

        /*账户不能包含特殊字符*/
        String vaildPattern = "[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";//这里表示特殊字符
        Matcher matcher = Pattern.compile(vaildPattern).matcher((userAccount));
        if(matcher.find()){ //找到特殊字符就返回-1
            throw new BusinessException(ErrorType.PARAMS_ERROR);

        }

        /*密码加密*/

        String newPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());


        /*查询用户是否存在*/
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userAccount",userAccount);//这里的userAccount是上面形参传过来的，这俄格语句表示根据这个userAccount查询有多少条语句
        queryWrapper.eq("userPassword",newPassword);
        User user = this.getOne(queryWrapper);
        if(user == null){
//            throw new BusinessException(ErrorType.PARAMS_ERROR);
            return null;
        }

        //3 对返回的用户信息进行脱敏(将password,updateTime,isDelete删除)
        User safeuser = getSafeUser(user);



        //4 记录用户的登录态(session记录)
        request.getSession().setAttribute(USER_LOGIN_STATE,safeuser);

        return safeuser;
    }

    /**
     * 脱敏方法
     * @param user
     * @return
     */
    @Override
    public User getSafeUser(User user){
        if(user == null){
            throw new BusinessException(ErrorType.NULL_ERROR);
        }
        User safeUser = new User();
        safeUser.setId(user.getId());
        safeUser.setUsername(user.getUsername());
        safeUser.setUserAccount(user.getUserAccount());
        safeUser.setAvatar(user.getAvatar());
        safeUser.setGender(user.getGender());
        safeUser.setPhone(user.getPhone());
        safeUser.setEmail(user.getEmail());
        safeUser.setUserStatus(user.getUserStatus());
        safeUser.setRole(user.getRole());
        safeUser.setCreateTime(user.getCreateTime());
        safeUser.setTags(user.getTags());
        return safeUser;
    }

    /**
     * 注销逻辑
     * @param request
     */
    @Override
    public int UserLogout(HttpServletRequest request) {
        //之前登录时候定义的session的键为常量
        request.removeAttribute(USER_LOGIN_STATE);
        return 1;
    }

    /**
     * 根据标签搜索用户【使用内存的方式进行搜索查询】
     * @param tagNameList：用户要拥有的标签
     * @return
     */
    @Override
    public List<User> searchUserByTags(List<String> tagNameList) {
        //判断是否为空
        if(CollectionUtils.isEmpty(tagNameList)){
            throw new BusinessException(ErrorType.PARAMS_ERROR);
        }

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        List<User> userList = userMapper.selectList(queryWrapper);
        Gson gson = new Gson();

        return userList.stream().filter((user) -> {
            String tagsStr = user.getTags();
            if(StringUtils.isBlank(tagsStr)){
                return false;
            }
            //使用Gson将字符串转化为json
            Set<String> tempTagNameSet = gson.fromJson(tagsStr,new TypeToken<Set<String>>(){}.getType());
            tempTagNameSet = Optional.ofNullable(tempTagNameSet).orElse(new HashSet<>());
            for(String tagName : tagNameList) {
                if (!tempTagNameSet.contains(tagName)) {
                    return false;
                }
            }
            return true;
        }).map(this::getSafeUser).collect(Collectors.toList());
    }

    /**
     * 用户修改个人信息的功能
     * @param user：用户所要修改的信息
     * @param loginUser：当登录的用户信息
     * @return
     */
    @Override
    public int updateUser(User user,User loginUser) {
        /* 前端的user页面需要修改用户的信息，那如何判断用户是否能修改呢
           1、用户只能修改自己的信息
           2、管理员可以修改任何用户的信息
        */

        /*如果当前登录的用户是管理员，允许更新任何用户*/
        if(isAdmin(loginUser)){
            //那如何进行更新修改呢？理论上只需要userMapper.updateById(user)这样就能更新数据库中的
            //mybatis会自动根据user中的id属性查找到相对应的用户进行更新
            //但是我们要进行更为严密的判断，需要先判断更新过来的用户id是否为空，并且这个用户是否存在。
            long id = user.getId();
            if(id <= 0){
                throw new BusinessException(ErrorType.PARAMS_ERROR);
            }
            User olderUser = userMapper.selectById(id);
            if(olderUser == null){
                throw new BusinessException(ErrorType.NULL_ERROR);
            }
            return userMapper.updateById(user);
        }

        /*如果当前用户修改的自己的信息*/
        long id = user.getId();
        if(id <= 0){
            throw new BusinessException(ErrorType.PARAMS_ERROR);
        }
        //如果过所要修改的用户信息的id等于登录用户的id则是用一个人
        if(id == loginUser.getId()){
            User olderUser = userMapper.selectById(id);
            if(olderUser == null){
                throw new BusinessException(ErrorType.NULL_ERROR);
            }
            return userMapper.updateById(user);
        }else{
            throw new BusinessException(ErrorType.NO_AUTH);
        }
    }

    /**
     * 获取当前登录用户的信息
     * @param request
     * @return
     */
    @Override
    public User getLoginUser(HttpServletRequest request) {
        if(request == null) {
            return null;
        }

        //获取当前登录用户的信息
        User loginUser = (User) request.getSession().getAttribute(USER_LOGIN_STATE);

        //如果当前登录的用户信息为空，则用户修改的不是自己的信息，抛出异常无权限。
        if(loginUser == null){
            throw new BusinessException(ErrorType.NO_AUTH);
        }
        return loginUser;
    }

    /**
     * 判断是否为管理员
     * @param request
     * @return
     */
    @Override
    public boolean isAdmin(HttpServletRequest request) {
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        User user = (User) userObj;
        //这里的user == null的判断是为了防止session的值没有去到，出现空指针异常
        if(user == null || user.getRole() != ADMIN_ROLE){
            return false;
        }
        return true;
    }

    /**
     * 判断是否为管理员【重载】
     * @param loginUser
     * @return
     */
    @Override
    public boolean isAdmin(User loginUser) {
        //这里的user == null的判断是为了防止session的值没有去到，出现空指针异常
        if(loginUser == null || loginUser.getRole() != ADMIN_ROLE){
            return false;
        }
        return true;
    }

    /**
     * 根据标签搜索用户【使用SQL的方式进行搜索查询】
     * @param tagNameList：用户要拥有的标签
     * @return
     */
    @Deprecated//该注解表示此方法已过时
    private List<User> searchUserByTagsBySQL(List<String> tagNameList) {
        //判断是否为空
        if(CollectionUtils.isEmpty(tagNameList)){
            throw new BusinessException(ErrorType.PARAMS_ERROR);
        }

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();

        for(String tagName : tagNameList){
            queryWrapper = queryWrapper.like("tags",tagName);
        }

        List<User> userList = userMapper.selectList(queryWrapper);


        //利用函数式接口对userList进行脱敏，并返回。
        return userList.stream().map(this::getSafeUser).collect(Collectors.toList());
    }

}




